package oop.lab.domain.game;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

import oop.lab.domain.board.Board;
import oop.lab.domain.board.Direction;
import oop.lab.domain.board.Location;
import oop.lab.domain.board.Piece;
import oop.lab.domain.board.PieceColor;

public class ReversiGame implements Game {
    private final Board board;
    private boolean finished = false;
    private PieceColor winner = null;
    private PieceColor currentPieceColor;

    public ReversiGame() {
        this.board = new Board(8);
        // 初始化棋盘中心4子
        board.placePiece(Location.of(3, 3), PieceColor.WHITE);
        board.placePiece(Location.of(3, 4), PieceColor.BLACK);
        board.placePiece(Location.of(4, 3), PieceColor.BLACK);
        board.placePiece(Location.of(4, 4), PieceColor.WHITE);
        currentPieceColor = PieceColor.BLACK;
    }

    public ReversiGame(Board board, PieceColor currentPieceColor) {
        this.board = board;
        this.currentPieceColor = currentPieceColor;
    }

    /**
     * 用于测试的⽅法。
     */
    public static ReversiGame ofGameWithFinishState() {
        PieceColor B = PieceColor.BLACK;
        PieceColor W = PieceColor.WHITE;
        PieceColor[][] grid = {
                { B, B, B, B, B, B, B, B },
                { B, B, B, B, B, B, B, B },
                { B, B, B, B, B, B, B, B },
                { B, B, B, W, null, B, B, B },
                { B, B, B, null, W, B, B, B },
                { B, B, B, B, B, B, B, B },
                { B, B, B, B, B, B, B, B },
                { B, B, B, B, B, B, B, B }
        };
        Board board = new Board(grid);
        return new ReversiGame(board, PieceColor.WHITE);
    }

    public String getGameType() {
        return "reversi";
    }
    /**
     * 当前用户执⾏⼀步棋
     */
    public boolean placePiece(Location loc) {
        if (!board.isValidPlacement(loc))
            throw new GameException("非法位置:" + loc.toString());
        List<Piece> pieces = getPiecesAttactedBy(loc, currentPieceColor);
        if (pieces.isEmpty())
            throw new GameException("此处无可攻击的棋子:" + loc.toString());

        board.placePiece(loc, currentPieceColor);
        flipPieces(pieces);
        currentPieceColor = currentPieceColor.oppositeColor();
        if (checkFinished()) {
            winner = getWinner();
            finished = true;
        }
        return true;
    }

    /**
     * 跳过当前⽤户执⾏⼀步棋
     */
    public boolean pass() {
        if (!shouldPass())
            throw new GameException("此处不能跳过");
        currentPieceColor = currentPieceColor.oppositeColor();
        return true;
    }

    public boolean shouldPass() {
        return getAllValidLocation(currentPieceColor).isEmpty();
    }

    private boolean isValidPlace(Location location, PieceColor pieceColor) {
        return !getPiecesAttactedBy(location, pieceColor).isEmpty();
    }

    /**
     * 返回沿着pieces被pieceColor颜色棋子攻击的棋子。被攻击的所有棋子的含义是：
     * 被pieceColor的棋子夹住的连续的所有其它颜色的棋子。
     */
    private List<Piece> getAttactedPieces(PieceColor pieceColor, List<Piece> pieces) {

        List<Piece> affectedPieces = new ArrayList<>();
        PieceColor oppositeColor = pieceColor.oppositeColor();

        for (Piece piece : pieces) {
            if (piece.getColor() == oppositeColor) {
                affectedPieces.add(piece);
            } else if (piece.getColor() == pieceColor) {
                return affectedPieces;
            } else {
                return new ArrayList<>();
            }
        }
        return new ArrayList<>();
    }

    /*
     * 计算被piece攻击的棋子，被攻击指的是沿着所有方向，被执⾏方夹击的所有棋子。
     */
    private List<Piece> getPiecesAttactedBy(Location location, PieceColor pieceColor) {
        return Stream.of(Direction.getAllDirections())
                .map(dir -> getAttactedPieces(
                        pieceColor,
                        board.getLine(location, dir)))
                .flatMap(List::stream)
                .toList();
    }

    /**
     * 翻转指定位置的棋子
     */
    public void flipPieces(List<Piece> pieces) {
        for (Piece piece : pieces) {
            board.replacePiece(
                    piece.getLocation(),
                    piece.getColor().oppositeColor());
        }
    }

    public Board getBoard() {
        return board;
    }

    /**
     * 计算执⾏方可以放置的所有位置。
     */
    public List<Location> getAllValidLocation(PieceColor piece) {
        return Stream.of(board.getAll(true))
                .filter(each -> !each.isOccupied())
                .filter(each -> isValidPlace(each.getLocation(), piece))
                .map(each -> each.getLocation())
                .toList();
    }

    /**
     * 计算某种颜色的棋子数量
     */
    public int getPieceCount(PieceColor piece) {
        return board.getPieceCount(piece);
    }

    // 游戏持续进⾏，直到棋盘填满或双⽅都⽆合法落⼦。
    public boolean checkFinished() {
        if (this.board.getAll(false).length == 64)
            return true;
        for (PieceColor pieceColor : PieceColor.allColors()) {
            if (!getAllValidLocation(pieceColor).isEmpty())
                return false;
        }
        return true;
    }

    public PieceColor getWinner() {
        // 游戏结束，并且棋子多的一方获胜
        if (finished) {
            if (getPieceCount(PieceColor.BLACK) > getPieceCount(PieceColor.WHITE))
                return PieceColor.BLACK;
            else
                return PieceColor.WHITE;
        }
        return null;
    }

    public PieceColor getCurrentPlayer() {
        return currentPieceColor;
    }

    public boolean isOver() {
        return finished;
    }

    public PieceColor getWinnerColor() {
        return winner;
    }
}